#!/usr/bin/env python
# -*- encoding: utf-8 -*-
'''
@File    :   Hero
@Time    :   2023/03/11 20:59:03
@author  :   Eval
@Version :   1.0
@Describe:   
'''
from lib.scripts.GC import *
from lib.scripts.EventHandle import *
from lib.scripts.AStart_Path import *
from lib.scripts.GameInit import *
from lib.scripts.Package import *
from lib.scripts.Enemys import *
from threading import Thread
from random import random

class Hero:
    def __init__(self,parent) -> None:
        import main
        self.parent:main.Run = parent
        self.packBag = self.parent.GameBag
        self.status = GC.GC_Hero

        self.localPos = [int(self.status["y"]) , int(self.status["x"])]  # 相对于地图的坐标点
        self.scenePos = [int(self.status["y"])*32 , int(self.status["x"])*32]
        self.image = GC.loadSurface(self.status["img"])
        # 创建一个用于绘制在ui上的 精灵,例如 对话事件
        self.imageUI = BlockSprite(self.image,{"animMax":0,"type":"null","key":-1,"index":0})
        self.imageUI.h = 48
        
        self.name = self.status["name"]
        self.lv = int(self.status["lv"])
        self.hp = int(self.status["hp"])
        self.hpMax = int(self.status["hpMax"])
        self.mana = int(self.status["mana"])
        self.manaMax = int(self.status["manaMax"])
        self.atk = int(self.status["atk"])
        self.atkSpeed = int(self.status["atkSpeed"])
        self.speed = int(self.status["speed"])
        self.defe = int(self.status["def"])
        self.mdef = int(self.status["mdef"])
        self.money = int(self.status["money"])
        self.exp = int(self.status["exp"])
        self.expMax = int(GC.GC_LevelConf[str(self.lv+1)]["need"])
        self.yellowKey = 0
        self.blueKey = 0
        self.redKey = 0

        # 当前动画帧
        self.animIndex = 0
        self.animMax = 4
        # 当前行走方向
        self.direction = self.status["direction"]
        self.dirDict = {"up":3,"down":0,"left":1,"right":2}
        # 是否正在行走
        self.isWalking = False
        # 步长 格子 / 帧数
        self.step = 32 // 8

        self.pathIndex = 0
        self.pathList = []
        self.map2D:list = []
        # 触发事件,使用多线程调用
        self.thEv = None

    def render(self):
        self.move()
        for index,i in enumerate(self.pathList):
            # 可视化寻路路径点
            if self.pathIndex <= index:
                pygame.draw.circle(self.parent.win,(211,211,211),(i.y*32+215,i.x*32+15),3)
        # 人物不能被路径点挡住
        self.parent.win.blit(self.image,[self.scenePos[0]+200,self.scenePos[1]-16],(int(self.animIndex)*32,self.dirDict[self.direction]*48,32,48))
        self.render_status()

    def go(self,x,y,map2d:list=None):
        if not map2d is None:
            self.pathList:list[Point] = map2d
            self.pathIndex = 0
        # 接收的坐标与鼠标打印的坐标需要是相反的
        self.next_x = x
        self.next_y = y
        if self.next_x < self.localPos[0]:
            self.direction = "left"
        elif self.next_x > self.localPos[0]:
            self.direction = "right"
        if self.next_y < self.localPos[1]:
            self.direction = "up"
        elif self.next_y > self.localPos[1]:
            self.direction = "down"
        self.isWalking = True

    def move(self):
        """玩家移动"""
        # 如果不是移动状态,那么跳出
        if not self.isWalking:
            return
        # 如果当前触发了事件
        if self.parent.evHandle.isActive():
            return
        #  记得需要将状态改为 真, 否则允许行走之后也会暂停行动
        self.isWalking = True

        dest_x = self.next_x *32
        dest_y = self.next_y *32
        # 判断当前需要移动的目标点是否有事件
        posEvent = self.parent.mapLogic.getFloorEvents()
        if posEvent.get(f"{self.next_y},{self.next_x}"):
            self.isWalking = False
            self.stopMove()
            self.thEv = Thread(target=self.parent.evHandle.contactEvent,args=(posEvent,self.next_y,self.next_x),daemon=True).start()
            return
        
        # 判断 是否有其他图块
        if self.map2D[self.next_y][self.next_x] != 0:
            if not self.moveEvent(self.next_y,self.next_x):
                return
            self.isWalking = True

        if self.scenePos[0] < dest_x:
            self.scenePos[0] += self.step
            if self.scenePos[0] >= dest_x:
                self.scenePos[0] = dest_x

        elif self.scenePos[0] > dest_x:
            self.scenePos[0] -= self.step
            if self.scenePos[0] <= dest_x:
                self.scenePos[0] = dest_x

        if self.scenePos[1] < dest_y:
            self.scenePos[1] += self.step
            if self.scenePos[1] >= dest_y:
                self.scenePos[1] = dest_y

        elif self.scenePos[1] > dest_y:
            self.scenePos[1] -= self.step
            if self.scenePos[1] <= dest_y:
                self.scenePos[1] = dest_y

        self.localPos[0] = self.scenePos[0] // 32
        self.localPos[1] = self.scenePos[1] // 32

        self.animIndex = (self.animIndex + 0.5) % 4

        if self.scenePos[0] == dest_x and self.scenePos[1] == dest_y:
            self.animIndex = 0
            if self.pathList is None:
                self.stopMove()
                return
            if self.pathIndex >= len(self.pathList)-1:
                self.stopMove()
                return
            self.pathIndex += 1
            pos = self.pathList[self.pathIndex]
            self.go(pos.y,pos.x)

    def render_status(self):
        """渲染主角属性"""
        yk = self.packBag.getByPackItemName("黄钥匙")
        if not yk is None:
            self.yellowKey = yk.number
        bk = self.packBag.getByPackItemName("蓝钥匙")
        if not bk is None:
            self.blueKey =  bk.number
        ek = self.packBag.getByPackItemName("红钥匙")
        if not ek is None:
            self.redKey =  ek.number
        
        bx = -1
        by = 0
        for i in range(112):
            self.parent.win.blit(GC.GC_GameSurfaceCache.get("terrains"),(bx*32+10,by*32),(0,0,32,32))
            bx += 1
            if bx >= 6:
                by += 1
                bx = -1
        status = f"名字:{self.name}\n\n等级:{self.lv}\n\n经验值:{self.exp}/{self.expMax}\n\n生命:{self.hp}/{self.hpMax}\n\n魔力:{self.mana}/{self.manaMax}\n\n攻击力:{self.atk}\n\n防御力:{self.defe}"
        status += f"\n\n金币:{self.money}\n\n黄钥匙:{self.yellowKey}\n\n蓝钥匙:{self.blueKey}\n\n红钥匙:{self.redKey}"
        self.parent.GameFont.render_multilineText(5,5,status,200,fontSize=14)

    def setHeroPos(self,x:int=0,y:int=0,loc:list=None):
        """设置勇士位置,如切换楼层后,将下一层的坐标传进来"""
        
        # 如果还在移动中,那么中止移动
        if self.isWalking:
            self.stopMove()
        if not loc is None:
            x,y = int(loc[1]),int(loc[0])
        self.localPos = [int(x),int(y)]  # 相对于地图的坐标点
        self.scenePos = [int(x)*32 , int(y)*32]

    def stopMove(self):
        """停止移动"""
        self.animIndex = 0
        self.pathIndex = 0
        self.isWalking = False
        self.pathList.clear()


    def moveEvent(self,x:int,y:int)->bool:
        """主角移动过程中触发事件处理"""
        self.isWalking = False
        block:dict = GC.getByPosSource(self.map2D[x][y])
        # 是否有触发器
        if not block.get("trigger") is None and block.get("trigger") != "null":
            BSprite:BlockSprite = self.parent.GInit.FBCache.get(f"{y}-{x}")
            # 如果门已经被激活过了, 那么就不往下执行了
            if not BSprite.active:
                return False
            if block.get("triggerKey"):
                # 判断玩家是否有这个触发器所需要的道具
                item:Item = self.packBag.getByPackItemKey(block["triggerKey"])
                # 处理开门逻辑,
                if item is not None and item.number >= 1:
                    BSprite.isPlayAnim = True
                    self.packBag.rmPackItemKey(block["triggerKey"])
                    BSprite.active = False
                    self.stopMove()
                    # 播放开门音效
                    self.parent.GameMusic.PlaySound("door.mp3")
                    # 开门之后需要暂停,
                    return False
                else:
                    ShowDiaLog.showTips("你的钥匙不够啦")
                    print_error("你的钥匙不够啦")
            else:
                ShowDiaLog.showTips("当前图块没有设置触发器,无法通行噢")


        # 如果是道具,那么直接加到背包里面继续行走,不停留
        if block["type"] == "items":
            self.packBag.addItem(block["key"],block["number"])
            self.parent.mapLogic.updataFPoint(x,y,0)
            ShowDiaLog.showTips(f"获取道具:{block['name']}×{block['number']}")
            return True
        
        # 如果是怪物, 那么准备战斗
        if block["type"] == "enemys":
            monster:Enemys = self.parent.GInit.FBCache[f"{y}-{x}"]
            self.parent.GameDuel.startPvP(self,monster)
        
        self.stopMove()
        return False
    
    def clashOver(self,monster:Enemys):
        """执行战斗结束的逻辑, 根据传进来的怪物数据,获得对应的奖励"""
        self.upgrade(monster.exp)
        self.addMoney(monster.money)
        # 战斗结束之后有 20%的几率获得天赐回馈, 生命恢复50
        if random() < 0.2:
            self.addHP(50)
            ShowDiaLog.showTips(f"恭喜:{self.name} 在战斗中有所领悟,生命值恢复了 50点")

    def addHP(self,value):
        """玩家增加生命"""
        self.hp += int(value)
        if self.hp > self.hpMax:
            self.hp = self.hpMax

    def addMoney(self,value:int):
        """主角获得金币"""
        self.money += int(value)
        # 设定一个最大的金币值, 9亿
        if self.money > 999999999:
            self.money = 999999999
            ShowDiaLog.showTips("已经达到金币持有上限了")
        else:
            ShowDiaLog.showTips(f"获得金币:{value}")

    def upgrade(self,value:int):
        """执行升级逻辑"""
        # 判断是否触发升级
        self.exp += int(value)
        if self.exp < self.expMax:
            return
        # 判断是否还有新的等级配置
        newLv = GC.GC_LevelConf.get(str(self.lv+1))
        if newLv is None:
            self.exp = self.expMax
            ShowDiaLog.showTips("您已经满级了")
            return
        self.exp = 0
        self.expMax = int(GC.GC_LevelConf[str(self.lv+1)]["need"])
        self.lv += 1
        self.hpMax += 100
        self.manaMax += 5
        self.atk += 1
        self.defe += 199
        ShowDiaLog.showTips("升级啦!!")

